package com.losrebellos.utils.collection 
{
	import flash.utils.Dictionary;

	/*
	 *
	 * @author los rebellos - ben@benoitvinay.com
	 *
	 */
	public final dynamic class DictionaryPlus extends Dictionary implements IDictionaryPlus
	{
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// VARIABLES
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		private var _weakKeys:Boolean;
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// CONSTRUCTOR
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function DictionaryPlus(weakKeys:Boolean = true)
		{
			super(_weakKeys = weakKeys);
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// DATA
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function add(key:Object, value:Object):Boolean
		{
			if(hasKey(key))
			{
				return false;
			}
			
			this[key] = value;
			_length++;
			
			return true;
		}
		public function tryAdding(key:Object, value:Object):Object
		{
			if(hasKey(key))
			{
				return getKey(key);
			}
			
			this[key] = value;
			_length++;
			
			return value;
		}
		public function remove(key:Object):Boolean
		{
			if(delete this[key])
			{
				_length--;
				return true;
			}
			
			return false;
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// APPLY A METHOD TO ALL ELEMENTS OF THE DICTIONARY
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function apply(method:String, ...args):void
		{
			for each(var value:Object in this)
			{
				if(args.length > 0)
				{
					value[method](args);
				}
				else
				{
					value[method]();
				}
			}
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// LENGTH
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		private var _length:int = 0;
		public function get length():int
		{
			return _length;
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// KEYS
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function hasKey(key:Object):Boolean
		{
			return getKey(key) != null;
		}
		public function getKey(key:Object):Object
		{
			return this[key];
		}
		public function getKeys():Array
		{
	        var keys:Array = [];
	        var key:Object;
	        for(key in this)
	        {
				keys.push(key);
	        }
			
	        return keys;
		}
		public function getValues():Array
		{
			var values:Array = [];
			var value:Object;
			for each(value in this)
			{
				values.push(value);
			}
			
			return values;
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// EMPTY
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function isEmpty():Boolean
		{
			return _length <= 0;
		}
		public function empty():Boolean
		{
			var success:Boolean = true;
			var key:Object;
			for(key in this)
			{
				if(!remove(key))
				{
					success = false;
				}
			}
			
			return success;
		}
		
		
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		// UTILS
		////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public function clone():DictionaryPlus
		{
			var dictionary:DictionaryPlus = new DictionaryPlus(_weakKeys);
			var key:Object;
			for(key in this)
			{
				dictionary.add(key, this[key]);
			}
			
			return dictionary;
		}
		public function toString():String
		{
			return "DictionaryPlus: " + _length + " / " + getKeys();
		}
	}
}